
(function(){

	/**
	 * Node in double list
	 * @module utils
	 * @class ListNode
	 */
	var ListNode = G.GClass('Utils', 'ListNode');
	ListNode.prototype.__init = function(data) {
		this.data = data;
		this.next = null;
		this.prev = null;
	}

	/**
	 * A double list in Javascript.
	 * @module utils
	 * @class List
	 */
	var List = G.GClass('Utils', 'List');
	List.prototype.__init = function() {
		this.head = null;
		this.tail = null;
	}

	/**
	 * Clear the list
	 * @method clear
	 */
	List.prototype.clear = function() {
		this.head = null;
		this.tail = null;
	}

		/**
		 * Check if the list is empty.
		 * @method is_empty
		 * @return {boolean} true if the list is empty.
		 */
	List.prototype.is_empty = function() {
		return (this.head == null);
	}

		/**
		 * Check if the list has only one node.
		 * @method has_only_one
		 * @return {boolean} ture if the list is only one node.
		 */
	List.prototype.has_only_one = function() {
		if (this.head == null)	return false;
		return (this.head == this.tail);
	}

		/**
		 * Insert a node at head of the list.
		 * @method insert
		 */
	List.prototype.insert = function(node) {
		if (!this.head) {
			this.head = node;
			this.tail = node;
		} else {
			node.next = this.head;
			this.head.prev = node;
			this.head = node;
			node.prev = null;
		}
	}

	/**
	 * Append a node at tail of the list
	 * @method append
	 */
	List.prototype.append = function(node) {
		if (!this.tail) {
			this.head = node;
			this.tail = node;
		} else {
			node.prev = this.tail;
			node.next = null;
			this.tail.next = node;
			this.tail = node;
		}
	}

	/**
	 * Remove a node from it's list. 
	 * @method remove
	 * @param node {object} a instance of ListNode that will be removed from it's list
	 */
	List.prototype.remove = function(node) {
		if (node == this.head) {
			this.head = node.next;
		}
		if (node == this.tail) {
			this.tail = node.prev;
		}

		if (node.prev) {
			node.prev.next = node.next;
		}
		if (node.next) {
			node.next.prev = node.prev;
		}
	}

	/**
	 * Search the node in list by a value.
	 * @method search
	 * @param {object} dat the value to search by
	 * @param {function} func it will be called during the search. if the function 
	 * return true, the search will be stopped and current node will be returned.
	 * @return {ListNode} the node that match the value or null if found nothing 
	 * in the list.
	 */
	List.prototype.search = function(dat, func) {
		if (typeof(func) == 'function') {
			for (var n = this.head; n != null; n = n.next) {
				if (func(n.data, dat)) {
					return n;
				}
			}
		} else {
			for (var n = this.head; n != null; n = n.next) {
				if (n.data == dat) {
					return n;
				}
			}
		}
		return null;
	}
})();

